Now that we have our animation created and we have an animation instance in our tool, it's time to
load this animation onto our humanoid from our local script.
We can load animations from the server as well, but I find it to be more optimal to load animations
that will be run on a player's character from that player's client sided scripts.
This is because, like I mentioned in a previous lecture, the movement of limbs of a player are one
of the sole exceptions of things that are replicated directly from the client to the server and to the
rest of the clients.
That means if I run an animation from a local script on my character, everyone else will be able to
see it.
So in my local script, let's create a variable called anim.
And get a reference to the eating animation in my tool.
Next, I want to create a variable that stores my character.
And so I'll call this variable character and set it equal to player, character or player character
added.
Cohen.
Wait.
What am I doing here?
Well, the players character property may not have a model reference to it yet, as games may delay
the player's character from spawning or simply waiting for the player's character model to replicate.
In this instance, player character may return nil because it doesn't exist yet.
So we use the or operator here and wait for the character added event to fire and this event returns
the player's character.
So any time that player character is nil, our script will default to this event and wait for it to
fire.
The next thing I want to do here is get a reference to my character's humanoid.
So I'll create a variable called humanoid.
And now listen up, because what I'm about to tell you is very important.
When we join our game, we will have local scripts that get run immediately, meaning that they are
local scripts that exist in starter player scripts or in the starter UI or in tools that are in the
starter pack.
And when we join the game, they start executing.
Now the problem with this is that if there are any references to things in the workspace and replicated
storage wherever they may not have been replicated to our client yet because our client is still downloading
all the assets.
This means that any references to things that have not yet been downloaded will return nil, and that's
a big problem.
So to fix this, Roadblocks has a function that you can call when indexing an instance and it's called
wait for child.
What this function does is yields the script until the child has appeared, or if the child is already
there, then it doesn't yield.
So if this donut was placed in the starter pack and it immediately starts running, there is no guarantee
that everything in the tool will have replicated yet.
So that's when we should use wait for child.
Any time you anticipate that an object may not have been replicated yet, use wait for child.
Otherwise you don't ever need to use it.
You should never use this in server scripts or in situations where you don't expect a child of an instance
to not have been replicated yet.
And the reason we don't use it in server scripts is because everything in the game has already been
downloaded to the server.
It doesn't have to wait for anything.
So here where I reference my animation, I can actually replace the statement with weight for child.
That way, just in case the animation has not yet been replicated to the client, it yields the script
and waits for it to become downloaded.
Now the next thing I need to do is create another variable.
I'll call it animator.
And this will store the animator, for instance, that is a child of the humanoid.
This animator allows us to use animations onto our humanoid and returns a playable track that has been
specifically loaded on a player's character.
And since it's not guaranteed that the animator will have replicated, I will put wait for child here
to.
The last variable I need to make is called track.
And we'll store the result from the function that belongs to the animator, which is the load animation
function.
This function requires one parameter and that needs to be our animation instance.
OC.
We are now ready to start playing this animation.
Now, there's something else I'd like to mention here, and is that when we use this weight for child
function and weight for the humanoid, the interpreter actually doesn't know what instance we're waiting
for.
That's why when I indexed Humanoid, it doesn't really show you any of the humanoid properties.
It just shows you the generic properties that all instances have.
So how do I let the game know that this function will return a humanoid?
That way I can see all of the attributes that belong to a humanoid.
Well, I can put two coins here, and then afterward I can declare the type that this variable should
store.
And that type is going to be a humanoid.
Now when I index humanoid, I can see all the events that belong to the humanoid, like died jumping
and all the other properties like health.
I can also do the same for the animator.
I can say that this variable will store a animator, for instance.
And now if I index the animator, I can now see the load animation pop up where I didn't see it pop
up earlier when I was trying to access it.
One more thing is that since this animator type was previously unknown, the game won't know what the
track variables referencing, but it should now.
When I index it, you see all the properties for the track instance, such as stopped playing, ended
all that good stuff.
So moving on, let's implement this animation into my script and actually run the track so we can see
our player eating our donut.
So firstly, what I want to do is that when I activate this tool, I want to play the animation.
So after I set the cool down to True or the bounce, I'm going to reference my track and then call the
play function on it and it'll start playing my animation next.
What I can do is I can reference my track again and get access to a function and it should be called
get marker reach signal, and then I can pass in the string byte, which was the name of that animation
event we put in our animation.
So what this does is it returns the event that was at this bite marker, and that means I can connect
a function to it.
And inside this function, when the animation track reaches that byte point, then I can fire to the
server to heal me and then I can yield for the cool down before I set the DB bounce back to false.
Now the issue with this here is that if a player unequipped their tool while they're in the middle of
an animation, it'll look like they're eating error and I don't want that.
So what I can do is I can access an event in tool called Unequipped Connect a function to it.
And here what I can do is I can reference my track and then I can stop it at any point when the player
unequipped the tool.
If the track hasn't been played, it's fine.
This won't error.
And then the next thing I can do is I can set the d bounce to false in here just in case.
When I play this track, it doesn't reach the byte signal because it got stopped before then and I can
still set the cool down to false, even though we were never able to override it and set it to false
here.
Now there's another big issue with this, if you haven't noticed yet, and that's when every time I
click this tool, every time I activate it, I keep connecting a new function to this byte event.
Every single time I click, I'm connecting another function, another function, another function,
and eventually I'll connect so many functions that these few lines of code here will be running so many
times.
And I don't want that to happen.
So what I can do instead, I can access the equipped event, connect a function to it.
And in here, this is the only time I want to connect a function to the byte event.
That way I don't keep connecting so many every time I click and activate the tool.
And then what else I want to do is I want to store the return from this event, which is the function,
I'll call it byte function or connected byte function.
I won't assign it anything here, but I will assign it the return from here.
And since I have it stored in a variable now, when I unequipped my tool, I can go and disconnect this
event.
I can disconnect the function from this event.
That way we aren't building up so many functions that keep getting connected to these few lines of code
here.
So what this does, basically every time I equip my tool, I connect a function to this event.
And then when I unequipped my tool, I disconnect that function.
And this stops me from building up function after function to this event for me equipping my tool.
So now if I run my game, I should be able to see my animation and then I get healed by it.
Psych studios being a little weird.
There we go.
So if I damage myself a little bit and then grab my donut, if I eat it, I should see my animation.
Perfect.
And it's healing me and I can't spam click it either.
And if I equip it, re-equip it to do that a bunch of times to see whether or not it's building up a
bunch of functions to that event, that animation event.
And let me damage myself a little bit more.
And it's still only healing me by five.
That means that the clicked event isn't being fired more than once each time I bite on my donut.
Now, the last thing I want to do is I want to play a sound.
My donut gets eaten.
And in order for everyone to hear that, I have to do it on the server.
Because if I try to play a sound on the client, only that client will be able to hear it.
So let's find a sound.
Actually, let's go to the toolbox and let's go to the marketplace.
We can go to sounds or audio.
And then let's just search for, like, bite.
Okay, that didn't work.
Let's search for it.
Um.
Sure.
Yeah, this one will work so we can insert it here into our tool.
I'll just rename it to eat.
And then here my server script.
I'll create a reference to it.
I'll just call it sound.
I'll do script start Parent dot eat.
And then when they player clicks, I will just play this sound.
If I go back into my game and I run again.
Every time I eat my donut.
It should play the sound perfect.
Now, one more thing is that in the sound property, there's a couple of properties in here that tell
you how far away the sound can be heard.
So right now it's set to 10,000 studs.
So that means anyone, 10,000 studs away can actually hear the sound, which is way too far.
I'll set it to something more modest, like 35.
And then this other integer here tells me the distance.
I want the sound to start becoming more quiet, basically.
And they have a couple of modes here that I can do that with.
I'll try tapered so that way, as I get further and further away from Ted Studs, once I reached 35
studs, the sound is completely silent and when I reach 34 it gets slightly louder.
35 or I mean 33, slightly more louder.
Until you reach ten, it reaches the loudest and it doesn't change.
So from 0 to 10 studs away from the donat, the sound will be the same volume.
But once you get greater than ten studs away, then it will become quieter and quieter until it becomes
completely quiet at 35 studs.
So let's try it again here.
And if I put my camera super far away,
it's still kind of here.
It.
Oh, you know what?
I know exactly why it's acting a fool.
It's because I have to actually parent the sound to a part.
That way, the sound radiates from the part, because otherwise, the game thinks that the sound belongs
to the entire workspace.
So it's playing the sound for everyone everywhere.
And it's not decreasing the volume.
So let's fix that.
I got to change the reference here.
So I'll do handle Dot eat.
And now it should work.
Basically another logical error there.
It wasn't acting the way I wanted.
So I can't hear it from all the way over here if I zoom in closer.
Still can't hear it.
You can kind of hear it and I can fully hear it.
Perfect.
You might notice that we're holding this doughnut a little funny, and I actually show you how to change
that real quick.
If I go into my character model here, here I am.
Find my donut.
I can actually change the positioning of it.
So if I change it, like here, actually it's not moving.
Why is it a moving?
Oh, I have to unequipped it and re-equip it.
Can actually see.
I can move it around to a position I find better.
So maybe I wanted to hold it out a little bit further.
Maybe I want to hold it probably at 0.3.
And then maybe a little bit more to the right.
So I'll do point.
Two or maybe just 0.1.
There we go.
Now I'm holding my donut a little bit nicer so I can actually copy these numbers.
And in that position property, I can update it here so when I go and grab my donut.
It's sitting in my hand a little more nicely.
Okay, one more thing.
I promise.
If you want to change the name of the donut, just rename the tool.
I'll just name it to Blue Frosted Donut.
And that way, when I play my game.
And I got to pick it up.
You see the name right here?
Blue Frosted Doughnut.
Okay, so that's how you create a healing donut and robotics.
In the next lecture, we have another fun activity to complete.